#ifndef EXPRESSION_C__
#define EXPRESSION_C__

#include <stdlib.h>
#include "basic.h"
#include "type.h"

#if 0
import std.lib;
import basic;
import type.c;
#endif

enum ExpressionTag
{
	// basic expressions
	CHARACTER_LITERAL_EXPRESSION,
	INTEGER_LITERAL_EXPRESSION,
	NAME_EXPRESSION,
	STRING_LITERAL_EXPRESSION,

	// unary expressions
	DEREFERENCE_EXPRESSION,				// *left OR @left
	LOCATION_EXPRESSION,				// &left
	NEGATION_EXPRESSION,				// -left
	POSITIVISATION_EXPRESSION,			// +left
	NOT_EXPRESSION,						// !left
	BITWISE_COMPLEMENT_EXPRESSION,		// ~left

	// left-recursive expressions
	PARENTHESE_EXPRESSION,				// left(right)
	BRACKET_EXPRESSION,					// left[right]

	// cast expression
	CAST_EXPRESSION,					// (left) right

	// infix expressions
	MEMBER_EXPRESSION,					// left.right
	POINTER_MEMBER_EXPRESSION,			// left->right

	MULTIPLICATION_EXPRESSION,			// left * right
	DIVISION_EXPRESSION,				// left / right
	MODULUS_EXPRESSION,					// left % right

	ADDITION_EXPRESSION,				// left + right
	SUBTRACTION_EXPRESSION,				// left - right

	LEFT_SHIFT_EXPRESSION,				// left << right
	RIGHT_SHIFT_EXPRESSION,				// left >> right
	BITWISE_AND_EXPRESSION,				// left & right
	BITWISE_OR_EXPRESSION,				// left | right
	BITWISE_XOR_EXPRESSION,				// left ^ right

	EQUAL_EXPRESSION,					// left == right
	NOT_EQUAL_EXPRESSION,				// left != right
	LESS_THAN_EXPRESSION,				// left < right
	GREATER_THAN_EXPRESSION,			// left > right
	LESS_THAN_OR_EQUAL_EXPRESSION,		// left <= right
	GREATER_THAN_OR_EQUAL_EXPRESSION,	// left >= right

	LOGICAL_AND_EXPRESSION,				// left && right

	LOGICAL_OR_EXPRESSION,				// left || right

	COMMA_EXPRESSION					// left, right
};

struct Expression { enum ExpressionTag tag; void* left; void* right; };
struct Expression* allocateExpression(enum ExpressionTag, void*, void*);
void freeExpression(struct Expression*);

struct Expression* allocateExpression(
	enum ExpressionTag tag,
	void* left,
	void* right)
{
	struct Expression* r = malloc(sizeof(struct Expression));
	r->tag = tag;
	r->left = left;
	r->right = right;
	return r;
}

void freeExpression(struct Expression* f)
{
	if(f == NULL)
		return;

	if(f->tag == CHARACTER_LITERAL_EXPRESSION)
		freeCharacterLiteral(f->left);

	else if(f->tag == INTEGER_LITERAL_EXPRESSION)
		freeIntegerLiteral(f->left);

	else if(f->tag == NAME_EXPRESSION)
		freeName(f->left);

	else if(f->tag == STRING_LITERAL_EXPRESSION)
		freeStringLiteral(f->left);

	else if(f->tag == CAST_EXPRESSION)
	{
		freeType(f->left);
		freeExpression(f->right);
	}

	else
	{
		freeExpression(f->left);
		freeExpression(f->right);
	}

	free(f);
}

#endif
